import { describe, expect, it } from 'vitest';
import { deobfuscate, obfuscate } from '../../src/hammer/crypto.mts';

describe('crypto 模块测试', () => {
  describe('obfuscate 函数', () => {
    it('应该能够正确混淆字符串', () => {
      const original = 'hello world';
      const obfuscated = obfuscate(original, 5);

      // 检查是否包含步长信息
      expect(obfuscated).toMatch(/^#\d+#/);

      // 检查长度是否增加（根据步长和原始字符串长度）
      // 原始长度11，步长5，应该插入2个混淆字符
      expect(obfuscated.length).toBeGreaterThan(original.length);
    });

    it('应该使用默认参数进行混淆', () => {
      const original = 'hello world this is a test string';
      const obfuscated = obfuscate(original);

      expect(obfuscated).toMatch(/^#10#/);
    });

    it('应该使用自定义字符集进行混淆', () => {
      const original = 'hello';
      const charset = '!@#$%^&*()';
      const obfuscated = obfuscate(original, 2, charset);

      expect(obfuscated).toMatch(/^#2#/);

      // 检查混淆字符是否来自自定义字符集
      const stepEndIndex = obfuscated.indexOf('#', 1);
      const content = obfuscated.slice(stepEndIndex + 1); // 去掉步长信息
      const insertedChars = content
        .split('')
        .filter((_, index) => (index + 1) % 3 === 0);
      insertedChars.forEach((char) => {
        expect(charset).toContain(char);
      });
    });

    it('应该处理空字符串', () => {
      const result = obfuscate('');
      expect(result).toBe('#10#');
    });

    it('应该在无效参数时抛出错误', () => {
      expect(() => obfuscate('test', 0)).toThrow();
      expect(() => obfuscate('test', -1)).toThrow();
      expect(() => obfuscate('test', 1, '')).toThrow();
    });
  });

  describe('deobfuscate 函数', () => {
    it('应该能够正确还原混淆字符串', () => {
      const original = 'hello world';
      const obfuscated = obfuscate(original, 5);
      const restored = deobfuscate(obfuscated);

      expect(restored).toBe(original);
    });

    it('应该使用默认参数正确还原', () => {
      const original = 'hello world this is a test string';
      const obfuscated = obfuscate(original);
      const restored = deobfuscate(obfuscated);

      expect(restored).toBe(original);
    });

    it('应该使用自定义字符集正确还原', () => {
      const original = 'hello world';
      const charset = '!@#$%^&*()';
      const obfuscated = obfuscate(original, 3, charset);
      const restored = deobfuscate(obfuscated);

      expect(restored).toBe(original);
    });

    it('应该在无效格式时抛出错误', () => {
      expect(() => deobfuscate('invalid format')).toThrow();
      expect(() => deobfuscate('#0#test')).toThrow();
      expect(() => deobfuscate('#-1#test')).toThrow();
      expect(() => deobfuscate('#abc#test')).toThrow();
    });

    it('应该处理空内容的混淆字符串', () => {
      const result = deobfuscate('#5#');
      expect(result).toBe('');
    });
  });

  describe('混淆和还原集成测试', () => {
    it('应该能够完整地混淆和还原复杂字符串', () => {
      const original =
        '这是一段用于测试的长文本，包含中文和English以及123456数字和特殊符号！@#￥%……&*（）';
      const obfuscated = obfuscate(original, 7);
      const restored = deobfuscate(obfuscated);

      expect(restored).toBe(original);
    });

    it('应该能够处理大量数据', () => {
      const original = 'a'.repeat(1000);
      const obfuscated = obfuscate(original, 10);
      const restored = deobfuscate(obfuscated);

      expect(restored).toBe(original);
      // 检查混淆后长度是否正确增加
      // 1000个字符，每10个字符插入1个混淆字符，应该插入 floor((1000-1)/10) = 99 个混淆字符
      // 头部信息长度为 2 + String(10).length = 4
      expect(obfuscated.length).toBe(1000 + 4 + 99);
    });
  });
});
